package org.example.tmp;

import java.io.IOException;
import java.math.BigInteger;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.regex.Pattern;

public class TcpServer {
    //准备两个东西  轮询器（叫号系统）+缓冲区（等候区）
    private Selector selector;

    private int port;

    public TcpServer(int port) {
        try {
            this.port = port;
            ServerSocketChannel socketChannel = ServerSocketChannel.open();
            socketChannel.bind(new InetSocketAddress(this.port));
            //为了兼容BIO NIO默认使用阻塞
            socketChannel.configureBlocking(false);

            //叫号系统工作
            selector = Selector.open();

            //开门营业
            socketChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void listen() {
        System.out.println("listen on " + this.port + ".");
        try {
            while (true) {
                selector.select();
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    iterator.remove();
                    try {
                        if (key.isValid()) {
                            process(key);
                        }
                    } catch (IOException e) {
                        key.cancel();
                        key.channel().close();
                        e.printStackTrace();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void process(SelectionKey key) throws IOException {
        if (key.isAcceptable()) {
            ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
            SocketChannel channel = serverSocketChannel.accept();
            channel.configureBlocking(false);
            channel.register(selector, SelectionKey.OP_READ);
        } else if (key.isReadable()) {
            SocketChannel channel = (SocketChannel) key.channel();
            int len;
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            while ((len = channel.read(buffer)) > 0) {
                buffer.flip();
                String content = new String(buffer.array(), 0, len);
                //在KEY上携带一个附件，一会儿写出去
                key.attach(content);
                System.out.println("读取内容：" + len + ":" + content);
            }
            channel.register(selector, SelectionKey.OP_WRITE);
        } else if (key.isWritable()) {
            SocketChannel channel = (SocketChannel) key.channel();
            String attachment = (String) key.attachment();
            System.out.println("输出：" + attachment);
            channel.write(ByteBuffer.wrap(("attachment").getBytes()));
            //channel.close();
            channel.register(selector, SelectionKey.OP_READ);
        }
    }

    public static String getSuitableString(byte[] bytes, int len) {
        if (bytes == null || bytes.length == 0) {
            return "";
        }
        byte[] buffer = new byte[len];
        System.arraycopy(bytes, 0, buffer, 0, len);
        String suitableParseString = new String(buffer);
        if (Pattern.compile("^[0-9a-zA-Z\\-\\+\\.\\*\\s\\!\\@\\(\\)\\#\\=\\?\\,\\$~\\|\\&\\^\\_]*$").matcher(suitableParseString).matches()) {
            return "ASCII>" + suitableParseString;
        }
        suitableParseString = new BigInteger(1, buffer).toString(16);
        if (Pattern.compile("^[0-9a-zA-Z\\-\\+\\.\\*\\s\\!\\@\\(\\)\\#\\=\\?\\,\\$~\\|\\&\\^\\_]*$").matcher(suitableParseString).matches()) {
            suitableParseString = toHexFormal(suitableParseString);
            return "HEX>" + suitableParseString;
        }
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < buffer.length; i++) {
            stringBuilder.append(String.valueOf(buffer[i]));
            if (i < buffer.length - 1) {
                stringBuilder.append(" ");
            }
        }
        return "UNKNOWN>" + stringBuilder.toString();
    }

    public static String toHexFormal(String src) {
        if (src == null) {
            return "";
        }
        src = src.replaceAll("\\s+", "").replaceAll("[^0-9a-fA-FX]", "");
        char[] chars = src.toCharArray();
        StringBuilder sb = new StringBuilder();
        int i = 0, len = chars.length % 2 == 0 ? chars.length : chars.length - 1;
        for (; i < len; i++) {
            sb.append(chars[i]);
            sb.append(chars[++i]);
            sb.append(" ");
        }
        if (i < chars.length) {
            sb.append(chars[i]);
        }
        return sb.toString().trim().toUpperCase();
    }

    public static void main(String[] args) {
        new org.example.tmp.TcpServer(8080).listen();
    }
}
